import os
import sqlite3
import numpy
from numpy import sin, cos, arcsin, arctan2
import math
PI = math.pi
D2R = PI / 180.0
R2D = 1.0 / D2R


def euler(ai_in, bi_in, select, b1950=False, dtype='f8'):
    """
    NAME:
        euler
    PURPOSE:
        Transform between Galactic, celestial, and ecliptic coordinates.
    CALLING SEQUENCE:
        long_out, lat_out =
            euler(long_in, lat_in, type, b1950=False, dtype='f8')
    INPUTS:
        long_in - Input Longitude in DEGREES, scalar or vector.
        lat_in  - Input Latitude in DEGREES
        select  - Integer (1-6) specifying type of coordinate transformation.
        select   From          To        |   select      From            To
        1     RA-Dec (2000)  Galactic   |     4       Ecliptic      RA-Dec
        2     Galactic       RA-DEC     |     5       Ecliptic      Galactic
        3     RA-Dec         Ecliptic   |     6       Galactic      Ecliptic
        Celestial coordinates (RA, Dec) should be given in equinox J2000
        unless the b1950=True keyword is set.
    OUTPUTS:
        long_out - Output Longitude in DEGREES
        lat_out  - Output Latitude in DEGREES
    INPUT KEYWORD:
        b1950 - If this keyword is true then input and output
                celestial and ecliptic coordinates should be given in equinox
                B1950.
    REVISION HISTORY:
        Written W. Landsman,  February 1987
        Adapted from Fortran by Daryl Yentis NRL
        Converted to IDL V5.0   W. Landsman   September 1997
        Made J2000 the default, added /FK4 keyword  W. Landsman December 1998
        Add option to specify SELECT as a keyword W. Landsman March 2003
        Converted from IDL to numerical Python: Erin Sheldon, NYU, 2008-07-02
    """

    # Make a copy as an array. ndmin=1 to avoid messed up scalar arrays
    ai = numpy.array(ai_in, ndmin=1, copy=True, dtype=dtype)
    bi = numpy.array(bi_in, ndmin=1, copy=True, dtype=dtype)

    twopi = 2.0 * PI
    fourpi = 4.0 * PI

    #   J2000 coordinate conversions are based on the following constants
    #   (see the Hipparcos explanatory supplement).
    #  eps = 23.4392911111d           Obliquity of the ecliptic
    #  alphaG = 192.85948d            Right Ascension of Galactic North Pole
    #  deltaG = 27.12825d             Declination of Galactic North Pole
    #  lomega = 32.93192d             Galactic longitude of celestial equator
    #  alphaE = 180.02322d            Ecliptic longitude of Galactic North Pole
    #  deltaE = 29.811438523d         Ecliptic latitude of Galactic North Pole
    #  Eomega  = 6.3839743d           Galactic longitude of ecliptic equator
    # Parameters for all the different conversions
    if b1950:

        equinox = '(B1950)'
        psi = numpy.array(
            [0.57595865315, 4.9261918136, 0.00000000000, 0.0000000000, 0.11129056012, 4.7005372834], dtype=dtype
        )
        stheta = numpy.array(
            [0.88781538514, -0.88781538514, 0.39788119938, -0.39788119938, 0.86766174755, -0.86766174755], dtype=dtype
        )
        ctheta = numpy.array(
            [0.46019978478, 0.46019978478, 0.91743694670, 0.91743694670, 0.49715499774, 0.49715499774], dtype=dtype
        )
        phi = numpy.array(
            [4.9261918136, 0.57595865315, 0.0000000000, 0.00000000000, 4.7005372834, 0.11129056012], dtype=dtype
        )

    else:

        equinox = '(J2000)'

        psi = numpy.array(
            [0.57477043300, 4.9368292465, 0.00000000000, 0.0000000000, 0.11142137093, 4.71279419371], dtype=dtype
        )
        stheta = numpy.array(
            [0.88998808748, -0.88998808748, 0.39777715593, -0.39777715593, 0.86766622025, -0.86766622025], dtype=dtype
        )
        ctheta = numpy.array(
            [0.45598377618, 0.45598377618, 0.91748206207, 0.91748206207, 0.49714719172, 0.49714719172], dtype=dtype
        )
        phi = numpy.array(
            [4.9368292465, 0.57477043300, 0.0000000000, 0.00000000000, 4.71279419371, 0.11142137093], dtype=dtype
        )

    # zero offset
    i = select - 1
    a = ai * D2R - phi[i]

    b = bi * D2R
    sb = sin(b)
    cb = cos(b)
    cbsa = cb * sin(a)
    b = -stheta[i] * cbsa + ctheta[i] * sb
    w, = numpy.where(b > 1.0)
    if w.size > 0:
        b[w] = 1.0
    bo = arcsin(b) * R2D

    a = arctan2(ctheta[i] * cbsa + stheta[i] * sb, cb * cos(a))

    ao = ((a + psi[i] + fourpi) % twopi) * R2D

    return ao, bo


def ec2eq(lam, beta, b1950=False, dtype='f8'):
    """
    NAME
        ec2eq
    PURPOSE
        Convert from ecliptic to equatorial coordinates in units of degrees.
    CALLING SEQUENCE
        ra,dec = eq2gal(lam, beta, b1950=False, dtype='f8')
    INPUTS
        lam,beta: Ecliptic coordinates.  May be Numpy arrays, sequences, or
            scalars as long as they are all the same length.  They must be
            convertible to a Numpy array with the specified datatype.
    KEYWORDS
        b1950:  If True, use b1950 coordiates.  By default j2000 are used.
        dtype:  The datatype of the output arrays.  Default is f8
    OUTPUTS
        ra,dec:  Equatorial longitude and latitude.  The returned value is
            always a Numpy array with the specified dtype
    REVISION HISTORY
        Created Erin Sheldon, NYU, 2008-07-02
    """
    ra, dec = euler(lam, beta, 4, b1950=b1950, dtype=dtype)
    ra = ra[0]/15.0
    tmp = int(ra)
    ra_out = str(tmp)+":"
    tmp = (ra - tmp)*60.0
    tmp1 = int(tmp)
    tmp2 = (tmp - tmp1)*60.0
    ra_out = ra_out + str(tmp1) + ":" + "%.4f"%tmp2

    dec = dec[0]
    tmp = int(dec)
    dec_out = str(tmp)+":"
    tmp = (dec - tmp)*60.0
    tmp1 = int(tmp)
    tmp2 = (tmp - tmp1)*60.0
    dec_out = dec_out + str(tmp1) + ":" + "%.3f"%tmp2
    return ra_out, dec_out


db_path = "%s/pulsar_source.db" % os.getcwd().replace("\\", "/")
psrcat_path = "%s/psrcat.db" % os.getcwd().replace("\\", "/")


def init_db():
    """
    初始化脉冲星源数据库，如果不存在的话
    """
    if not os.path.isfile(db_path):
        print("Data base init!")
        conn = sqlite3.connect(db_path)
        c = conn.cursor()
        #yapf:disable
        c.execute('''create table pulsar_source
            (
            jname VARCHAR(100) PRIMARY KEY NOT NULL,
            bname VARCHAR(100),
            rah  INT  NOT NULL,
            ram  INT  NOT NULL,
            ras  REAL NOT NULL,
            decd INT  NOT NULL,
            decm INT  NOT NULL,
            decs REAL NOT NULL,
            dm REAL
            )''')
        #yapf:enable
        c.close()
        conn.commit()
        conn.close()


def insert_db(jname, rah, ram, ras, decd, decm, decs, bname=None, dm=None):
    """
    在数据库中插入元素，如果已存在，更新

    Args:
        jname (str): J脉冲星名称
        bname (str): B脉冲星名称
        rah (int): 赤经时
        ram (int): 赤经分
        ras (float): 赤经秒
        decd (int): 赤纬度
        decm (int): 赤纬分
        decs (float): 赤纬秒
        dm (float): 消色散参数
    """
    conn = sqlite3.connect(db_path)
    c = conn.cursor()
    try:
        if bname != None:
            c.execute(
                "insert into pulsar_source values ('%s', '%s', %s, %s, %s, %s, %s, %s, %s)" %
                (jname, bname, str(rah), str(ram), str(ras), str(decd), str(decm), str(decs), str(dm))
            )
        else:
            c.execute(
                "insert into pulsar_source values ('%s', %s, %s, %s, %s, %s, %s, %s, %s)" %
                (jname, 'NULL', str(rah), str(ram), str(ras), str(decd), str(decm), str(decs), str(dm))
            )
    except:
        if bname != None:
            c.execute(
                "update pulsar_source set bname = '%s', rah = %s, ram = %s, ras = %s, decd = %s, decm = %s, decs = %s, dm = %s where jname = '%s';"
                % (bname, str(rah), str(ram), str(ras), str(decd), str(decm), str(decs), str(dm), jname)
            )
        else:
            c.execute(
                "update pulsar_source set bname = %s, rah = %s, ram = %s, ras = %s, decd = %s, decm = %s, decs = %s, dm = %s where jname = '%s';"
                % ('NULL', str(rah), str(ram), str(ras), str(decd), str(decm), str(decs), str(dm), jname)
            )
    c.close()
    conn.commit()
    conn.close()


def delete_dbj(jname):
    """
    从数据库中删除元素

    Args:
        jname (str): J脉冲星名称
    """
    conn = sqlite3.connect(db_path)
    c = conn.cursor()
    try:
        c.execute("delete from pulsar_source where jname = '%s';" % jname)
    except:
        print("Fail to delete!")
    c.close()
    conn.commit()
    conn.close()


def delete_dbb(bname):
    """
    从数据库中删除元素

    Args:
        bname (str): B脉冲星名称
    """
    conn = sqlite3.connect(db_path)
    c = conn.cursor()
    try:
        c.execute("delete from pulsar_source where bname = '%s';" % bname)
    except:
        print("Fail to delete!")
    c.close()
    conn.commit()
    conn.close()


def update_db(index, jname, rah, ram, ras, decd, decm, decs, bname=None):
    """
    在数据库中更新，如果脉冲星名称变更，删除原条目，增加新条目

    Args:
        index (int): 数据库中序号
        jname (str): J脉冲星名称
        bname (str): B脉冲星名称
        rah (int): 赤经时
        ram (int): 赤经分
        ras (float): 赤经秒
        decd (int): 赤纬度
        decm (int): 赤纬分
        decs (float): 赤纬秒
    """
    conn = sqlite3.connect(db_path)
    c = conn.cursor()
    if len(list(c.execute("select jname from pulsar_source where jname = '%s'" % jname))) != 0:
        if bname != None:
            c.execute(
                "update pulsar_source set bname = '%s', rah = %s, ram = %s, ras = %s, decd = %s, decm = %s, decs = %s, dm = %s where jname = '%s';"
                % (bname, str(rah), str(ram), str(ras), str(decd), str(decm), str(decs), str(dm), jname)
            )
        else:
            c.execute(
                "update pulsar_source set bname = %s, rah = %s, ram = %s, ras = %s, decd = %s, decm = %s, decs = %s, dm = %s where jname = '%s';"
                % ('NULL', str(rah), str(ram), str(ras), str(decd), str(decm), str(decs), str(dm), jname)
            )
    else:
        cursor = list(c.execute("select * from pulsar_source order by jname"))
        name_p = cursor[index][0]
        delete_db(name_p)
        c.execute(
            "insert into pulsar_source values ('%s', '%s', %s, %s, %s, %s, %s, %s, %s)" %
            (jname, bname, str(rah), str(ram), str(ras), str(decd), str(decm), str(decs), str(dm))
        )
    c.close()
    conn.commit()
    conn.close()


def select_db():
    """
    获取数据库中所有数据

    Returns:
        list: 数据库元素列表
    """
    conn = sqlite3.connect(db_path)
    c = conn.cursor()
    cursorj = list(c.execute("select jname from pulsar_source order by jname"))
    cursorb = list(c.execute("select bname from pulsar_source where bname != NULL order by bname"))
    cursor = cursorb + cursorj
    c.close()
    conn.commit()
    conn.close()
    return cursor


def select_dbj():
    """
    获取数据库中所有J脉冲星数据

    Returns:
        list: 数据库元素列表
    """
    conn = sqlite3.connect(db_path)
    c = conn.cursor()
    cursor = list(c.execute("select jname from pulsar_source order by jname"))
    c.close()
    conn.commit()
    conn.close()
    return cursor


def select_dbb():
    """
    获取数据库中所有B脉冲星数据

    Returns:
        list: 数据库元素列表
    """
    conn = sqlite3.connect(db_path)
    c = conn.cursor()
    cursor = list(c.execute("select bname from pulsar_source where bname is not NULL order by bname"))
    c.close()
    conn.commit()
    conn.close()
    return cursor


def select_db_jname(jname):
    conn = sqlite3.connect(db_path)
    c = conn.cursor()
    cursor = list(
        c.execute("select bname, rah, ram, ras, decd, decm, decs from pulsar_source where jname = '%s'" % jname)
    )
    c.close()
    conn.commit()
    conn.close()
    return cursor


def select_db_bname(bname):
    conn = sqlite3.connect(db_path)
    c = conn.cursor()
    cursor = list(
        c.execute("select jname, rah, ram, ras, decd, decm, decs from pulsar_source where bname = '%s'" % bname)
    )
    c.close()
    conn.commit()
    conn.close()
    return cursor


def find_content(content, i):
    para = list(filter(None, content[i].split(" ")))
    while para[0] != 'PSRB' and para[0] != 'PSRJ':
        i += 1
        para = list(filter(None, content[i].split(" ")))
    if para[0] == 'PSRB':
        bname = para[1]
        print(bname)
        i += 1
        para = list(filter(None, content[i].split(" ")))
        jname = para[1]
        i += 1
        para = list(filter(None, content[i].split(" ")))
        raj = para[1]
        i += 1
        para = list(filter(None, content[i].split(" ")))
        decj = para[1]
        if para[0] != 'DECJ':
            raj, decj = ec2eq(raj, decj)
    else:
        bname = None
        jname = para[1]
        i += 1
        para = list(filter(None, content[i].split(" ")))
        raj = para[1]
        i += 1
        para = list(filter(None, content[i].split(" ")))
        decj = para[1]
        if para[0] != 'DECJ':
            raj, decj = ec2eq(raj, decj)
    dm = None
    i += 1
    para = list(filter(None, content[i].split(" ")))
    while (para[0][0] != '@'):
        if para[0] == 'DM':
            dm = para[1]
        i += 1
        para = list(filter(None, content[i].split(" ")))
    i += 1
    raj = raj.split(":")
    decj = decj.split(":")
    rah = int(raj[0])
    try:
        ram = int(raj[1])
    except:
        ram = 0
    try:
        ras = float(raj[2])
    except:
        ras = 0.0
    decd = int(decj[0])
    try:
        decm = int(decj[1])
    except:
        decm = 0
    try:
        decs = float(decj[2])
    except:
        decs = 0.0
    if dm != None:
        dm = float(dm)
    else:
        dm = 'NULL'
    insert_db(jname, rah, ram, ras, decd, decm, decs, bname, dm)
    return i


if __name__ == "__main__":
    # init_db()
    # psrcat = open(psrcat_path)
    # content = psrcat.readlines()
    # psrcat.close()
    # i = 0
    # i = find_content(content, i)
    # while i < len(content) - 1:
    #     i = find_content(content, i)
    print(select_dbb())
    # ra, dec = ec2eq(53.92357, 54.61912)
    # print(ra,dec)
